package cn.lingyangwl.agile.common.datasource;

import cn.lingyangwl.agile.common.core.config.GlobalProperties;
import cn.lingyangwl.agile.common.datasource.mapper.CommonMapper;
import cn.lingyangwl.agile.model.constants.TenantCons;
import cn.lingyangwl.agile.model.constants.UserCons;
import cn.lingyangwl.agile.model.module.tenant.TenantContext;
import cn.lingyangwl.agile.tenant.core.TenantConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author shenguangyang
 */
@Slf4j
@Service
public class CommonService {
    @Resource
    private TenantConfig tenantConfig;
    @Resource
    private CommonMapper commonMapper;
    @Resource
    private GlobalProperties globalProperties;

    private static final Map<String, Boolean> dbTableName = new ConcurrentHashMap<>();

    /**
     * 检查表是否存在, 目前不支持多数据源
     */
    public boolean checkTableExists(String tableName) {
        try {
            Boolean isExist = dbTableName.get(tableName);
            if (Objects.nonNull(isExist)) {
                return isExist;
            }
            boolean ret = commonMapper.checkTableExists(tableName) > 0;
            dbTableName.put(tableName, ret);
            return ret;
        } catch (Exception e) {
            log.error("检查表是否存在失败", e);
        }
        return false;
    }

    /**
     * 删除数据
     */
    public void deleteAllDataByUserId(Long userId) {
        if (Objects.isNull(userId) || UserCons.ADMIN_ID.compareTo(userId) == 0) {
            return;
        }
        if (!globalProperties.getDeleteUserRelateData()) {
            return;
        }

        TenantContext.get().filterTenant(false);

        for (String tableName : tenantConfig.getDeleteUserDataTables()) {
            try {
                if (!checkTableExists(tableName)) {
                    continue;
                }
                Integer count = commonMapper.deleteAllDataByUserId(tableName, userId);
                if (count > 0) {
                    log.info("delete user data end ===> userId: {}, tableName: {}, size: {}", userId, tableName, count);
                }
            } catch (Exception e) {
                log.error("tableName: {}, userId: {}, error: {}", tableName, userId, e.getMessage());
            }
        }
    }

    /**
     * 删除数据
     */
    public void deleteAllDataByTenantId(Boolean isMainTenant, String tenantId) {
        if (Objects.isNull(tenantId) || TenantCons.SYSTEM_TENANT_ID.compareTo(tenantId) == 0) {
            return;
        }
        if (!globalProperties.getDeleteTenantRelateData()) {
            return;
        }

        TenantContext.get().filterTenant(false);
        if (isMainTenant) {
            for (String tableName : tenantConfig.getHasMainTenantIdTables()) {
                StopWatch stopWatch = StopWatch.createStarted();
                try {
                    if (!checkTableExists(tableName)) {
                        continue;
                    }
                    Integer count = commonMapper.deleteAllDataByMainTenantId(tableName, tenantId);
                    if (count > 0) {
                        log.info("delete tenant data ===> tenantId: {}, tableName: {}, size: {}, time: {} s",
                            tenantId, tableName, count, stopWatch.getTime(TimeUnit.SECONDS));
                    }
                } catch (Exception e) {
                    log.error("tableName: {}, tenantId: {}, error: {}", tableName, tenantId, e.getMessage());
                } finally {
                    stopWatch.stop();
                }
            }
        }

        for (String tableName : tenantConfig.getHasTenantIdTables()) {
            StopWatch stopWatch = StopWatch.createStarted();
            try {
                if (!checkTableExists(tableName)) {
                    continue;
                }
                Integer count = commonMapper.deleteAllDataByTenantId(tableName, tenantId);
                if (count > 0) {
                    log.info("delete tenant data ===> tenantId: {}, tableName: {}, size: {}, time: {} s",
                        tenantId, tableName, count, stopWatch.getTime(TimeUnit.SECONDS));
                }
            } catch (Exception e) {
                log.error("tableName: {}, tenantId: {}, error: {}", tableName, tenantId, e.getMessage());
            } finally {
                stopWatch.stop();
            }
        }
    }
}
